﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Reflection;
using System.IO;

namespace xtraSMSCore
{
    class PluginServices
    {
        public struct AvailablePlugin
        {
            public string AssemblyPath;
            public string ClassName;
        }

        public static AvailablePlugin[] FindPlugins(string strPath, string strInterface)
        {
            ArrayList Plugins = new ArrayList();
            string[] strDLLs = null;
            int intIndex = 0;
            Assembly objDLL = default(Assembly);

            //Go through all DLLs in the directory, attempting to load them
            strDLLs = Directory.GetFileSystemEntries(strPath, "*.dll");
            for (intIndex = 0; intIndex <= strDLLs.Length - 1; intIndex++)
            {
                try
                {
                    objDLL = Assembly.LoadFrom(strDLLs[intIndex]);
                    ExamineAssembly(objDLL, strInterface, Plugins);
                }
                catch (Exception)
                {
                }
                //Error loading DLL, we don't need to do anything special
            }

            //Return all plugins found
            AvailablePlugin[] Results = new AvailablePlugin[Plugins.Count];

            if (Plugins.Count != 0)
            {
                Plugins.CopyTo(Results);
                return Results;
            }
            else
            {
                return null;
            }
        }

        private static void ExamineAssembly(Assembly objDLL, string strInterface, ArrayList Plugins)
        {
            Type objInterface = default(Type);
            AvailablePlugin Plugin = default(AvailablePlugin);

            //Loop through each type in the DLL
            foreach (var typ in objDLL.GetTypes())
            {
                //Only look at public types
                if (typ.IsPublic == true)
                {
                    //Ignore abstract classes
                    if (!((typ.Attributes & TypeAttributes.Abstract) == TypeAttributes.Abstract))
                    {

                        //See if this type implements our interface
                        objInterface = typ.GetInterface(strInterface, true);

                        if ((objInterface != null))
                        {
                            //It does
                            Plugin = new AvailablePlugin();
                            Plugin.AssemblyPath = objDLL.Location;
                            Plugin.ClassName = typ.FullName;
                            Plugins.Add(Plugin);

                        }
                    }
                }
            }
        }

        public static object CreateInstance(AvailablePlugin Plugin)
        {
            Assembly objDLL = default(Assembly);
            object objPlugin = null;

            try
            {
                //Load dll
                objDLL = Assembly.LoadFrom(Plugin.AssemblyPath);

                //Create and return class instance
                objPlugin = objDLL.CreateInstance(Plugin.ClassName);
            }
            catch (Exception)
            {
                return null;
            }

            return objPlugin;
        }
    }
}
